using System;
using System.IO;
using System.Collections.Generic;
using System.Text;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using TamTam.SharePoint.SolutionManagement.WebServices;

namespace TamTam.SharePoint.SolutionManagement.MsBuildTasks {

    /// <summary>
    /// MSBuild Task that calls the <c>MsBuildDeployment.asmx</c> webservice and tries to deploy the
    /// Solution provided to the sharepoint farm at the <c>AdminUrl</c>.
    /// </summary>
    /// <example>
    ///     <![CDATA[
    ///     <UsingTask TaskName="TamTam.SharePoint.SolutionManagement.MsBuildTasks.SharePointSolutionDeployment" 
    ///         AssemblyName="TamTam.SharePoint.SolutionManagement" />    
    ///     <Target Name="Deployment">
    ///        <SharePointSolutionDeploymentTask 
    ///             AdminUrl="http://portal.tamtam.nl:1024/"
    ///             Solution="/Solution/TamTam.SharePoint.SolutionManagement.wsp"
    ///             DeploymentType="Deployment.Replace"
    ///             />
    ///     </Target>
    /// ]]>
    /// </example>
    public class SharePointSolutionDeployment: Task {

        /// <summary>
        /// default empty constructor
        /// </summary>
        public SharePointSolutionDeployment()
            : base() {
        }

        /// <summary>
        /// Deploy the sharepoint solution to a sharepoint server
        /// </summary>
        /// <returns>true if successfull</returns>
        public override bool Execute() {
            bool result = false;
            try {

                if (this.CentralAdminUrl != null) {
                    // contruct admin url
                    string url = this.CentralAdminUrl + "/_admin/ttsm/MsBuildDeployment.asmx";
                    if (this.CentralAdminUrl.EndsWith("/")) {
                        url = this.CentralAdminUrl + "_admin/ttsm/MsBuildDeployment.asmx";
                    }

                    // locate project folders
                    System.IO.DirectoryInfo projectdir = new System.IO.DirectoryInfo(System.IO.Path.GetDirectoryName(this.BuildEngine.ProjectFileOfTaskNode));
                    System.IO.DirectoryInfo solutiondir = projectdir.Parent;
                    
                    // connect to the webservice
                    SharePoint.SolutionManagement.WebServices.MsBuildDeployment mbd = new MsBuildDeployment();
                    // url
                    Log.LogMessage(MessageImportance.Normal, "Connecting to {0}", url);
                    mbd.Url = url;
                    // username/password provided?
                    if (string.IsNullOrEmpty(this.AdminDomain) || string.IsNullOrEmpty(this.AdminUser) || string.IsNullOrEmpty(this.AdminPassword)) {
                        // log in as the current build account
                        mbd.Credentials = System.Net.CredentialCache.DefaultNetworkCredentials;
                    }
                    else {
                        //connect with the supplied credentials
                        mbd.Credentials = new System.Net.NetworkCredential(
                            this.AdminUser,
                            this.AdminPassword,
                            this.AdminDomain);
                    }

                    // construct full filename
                    string file = solutiondir.FullName + this.Solution;
                    if (this.Solution.IndexOf(":\\") >= 0) // full pathname provided
                        file = this.Solution; 
                    else {
                        if ( this.Solution.StartsWith("/") || this.Solution.StartsWith("\\") )
                            file = solutiondir.FullName + this.Solution;
                        else
                            file = projectdir.FullName + this.Solution;
                    }

                    string solutionName = System.IO.Path.GetFileName(file);
                    Log.LogMessage(MessageImportance.Normal, "Uploading {0}", solutionName);
                    FileInfo fi = new FileInfo(file);
                    // read the sourcefile
                    using (System.IO.FileStream fs = fi.OpenRead()) {
                        byte[] bytes = new byte[fs.Length];
                        fs.Read(bytes, 0, bytes.GetLength(0));
                        if ( this.deploymentType == Deployment.Replace )
                            result = mbd.DeploySolution(solutionName, bytes, SharePoint.SolutionManagement.WebServices.Deployment.Replace);
                        else
                            result = mbd.DeploySolution(solutionName, bytes, SharePoint.SolutionManagement.WebServices.Deployment.Upgrade);
                    }
                    Log.LogMessage(MessageImportance.Normal, "Uploading complete");
                    Log.LogMessage(MessageImportance.Normal, "Upload result: {0}", result);

                    Console.WriteLine(string.Format("Upload result: {0}", result));
                }

            }
            catch (Exception exc) {
                Log.LogError("Unable to deploy solution: {0}",exc.Message);
            }
            return result ;
        }

        #region [ Required Properties for this buildtask ]

        private string adminUrl;
        private string adminDomain;
        private string adminUser;
        private string adminPassword;
        private string solution;
        private Deployment deploymentType = Deployment.Replace;

        /// <summary>
        /// Relative or absolute path to the solution file to deploy
        /// </summary>
        [Required]
        public string Solution {
            get { return solution; }
            set { solution = value; }
        }

        /// <summary>
        /// Url of the Central administraton
        /// </summary>
        [Required]
        public string CentralAdminUrl {
            get { return adminUrl; }
            set { adminUrl = value; }
        }

        /// <summary>
        /// What kind of deployment do we want, Upgrade does a inplace upgrade, Replace does a 
        /// retract and redeploy
        /// </summary>
        public string DeploymentType {
            get {
                if (this.deploymentType == Deployment.Replace) return "Replace";
                else return "Upgrade";
            }
            set {
                if (value  == "Replace") this.deploymentType = Deployment.Replace;
                else this.deploymentType = Deployment.Upgrade;
            }
        }

        /// <summary>
        /// Domain of the account to login to the central admin to,
        /// leave blank to use the current user
        /// </summary>
        public string AdminDomain {
            get { return adminDomain; }
            set { adminDomain = value; }
        }

        /// <summary>
        /// username of the account to login to the central admin to,
        /// leave blank to use the current user
        /// </summary>
        public string AdminUser {
            get { return adminUser; }
            set { adminUser = value; }
        }

        /// <summary>
        /// password of the account to login to the central admin to,
        /// leave blank to use the current user
        /// </summary>
        public string AdminPassword {
            get { return adminPassword; }
            set { adminPassword = value; }
        }


        #endregion
    }

    /// <summary>
    /// Type of Deployment to use with the <c>SharePointSolutionDeploymentTask</c> MsBuild task.
    /// </summary>
    public enum Deployment {
        Upgrade,
        Replace
    }
}
